#include "MBVec3.h"

#include <math.h>
#include <cstring>

/**
  * Constructs a new MBVec3 object with coordinates (0 0 0)
  */
MBVec3::MBVec3( void )
{
	mValues[0] = 0.0;
	mValues[1] = 0.0;
	mValues[2] = 0.0;
}

/**
  * Constructs a new MBVec3 object with the coordinates of the given double array
  *
  * @param values const pointer to the first element of a double array with three elements
  */
MBVec3::MBVec3( const double *values )
{
	memcpy( mValues, values, 3 * sizeof( double ) );
}

/**
  * Constructs a new MBVec3 object with the given coordinates
  *
  * @param v1 element v1
  * @param v2 element v2
  * @param v3 element v3
  */
MBVec3::MBVec3( const double &v1, const double &v2, const double &v3 )
{
	mValues[0] = v1;
	mValues[1] = v2;
	mValues[2] = v3;
}

/**
  * Calculates the cross product of this and the other vector and returns the
  * result.
  *
  * @param other other vector
  * @return cross product of this and the other vector
  */
MBVec3 MBVec3::Cross( const MBVec3 &other ) const
{
	return MBVec3(
		mValues[1] * other.mValues[2] - other.mValues[1] * mValues[2],
		mValues[2] * other.mValues[0] - other.mValues[2] * mValues[0],
		mValues[0] * other.mValues[1] - other.mValues[0] * mValues[1] );
}

/**
  * Calculates the dot product of this and the other vector and returns the
  * result. The value of the dot product is |this| * |other| * cos(alpha), where
  * |.| is the norm of a vector and alpha is the angle between these vectors.
  *
  * @param other other vector
  * @return dot product of this and the other vector
  */
double MBVec3::Dot( const MBVec3 &other ) const
{
	return mValues[0] * other.mValues[0] +
		   mValues[1] * other.mValues[1] +
		   mValues[2] * other.mValues[2];
}

/**
  * Normalizes this vector, which means that it is scaled to have length 1.
  */
void MBVec3::Normalize( void )
{
	double length = sqrt( mValues[0] * mValues[0] + mValues[1] * mValues[1] + mValues[2] * mValues[2] );

	if (length != 0.0)
	{
		mValues[0] /= length;
		mValues[1] /= length;
		mValues[2] /= length;
	}
}

/**
  * Returns a reference to the element at index
  *
  * @param index index of the element (0, 1 or 2)
  * @return reference to the element at index
  */
double &MBVec3::operator[]( const MBuint &index )
{
	return mValues[index];
}

/**
  * Returns a const reference to the element at index
  *
  * @param index index of the element (0, 1 or 2)
  * @return const reference to the element at index
  */
const double &MBVec3::operator[]( const MBuint &index ) const
{
	return mValues[index];
}

/**
  * Calculates the reverse of this vector and returns the result
  *
  * @return reverse of this vector
  */
MBVec3 MBVec3::operator-( void ) const
{
	return MBVec3( -mValues[0], -mValues[1], -mValues[2] );
}

/**
  * Calculates the difference between this and the other vector and returns the
  * result.
  *
  * @param other other vector
  * @return difference between this and the other vector
  */
MBVec3 MBVec3::operator-( const MBVec3 &other ) const
{
	return MBVec3(  mValues[0] - other.mValues[0],
					mValues[1] - other.mValues[1],
					mValues[2] - other.mValues[2] );
}

/**
  * Calculates the sum of this and the other vector and returns the
  * result.
  *
  * @param other other vector
  * @return sum of this and the other vector
  */
MBVec3 MBVec3::operator+( const MBVec3 &other ) const
{
	return MBVec3(  mValues[0] + other.mValues[0],
					mValues[1] + other.mValues[1],
					mValues[2] + other.mValues[2] );
}

/**
  * Calculates the product of this vector and value and returns the result.
  *
  * @param value scale factor to be multiplied with every single element of the vector
  * @return product of this vector and value
  */
MBVec3 MBVec3::operator*( const double &value ) const
{
	return MBVec3( mValues[0] * value, mValues[1] * value, mValues[2] * value );
}

/**
  * Calculates the quotient of this vector and value and returns the result.
  *
  * @param value divisor in the division operation. Every single element of the vector is divided by this value.
  * @return quotient of this vector and value
  */
MBVec3 MBVec3::operator/( const double &value ) const
{
	return MBVec3( mValues[0] / value, mValues[1] / value, mValues[2] / value );
}

/**
  * Calculates the dot product of first and second and returns the result. The
  * value of the dot product is |frist| * |second| * cos(alpha), where |.| is
  * the norm of a vector and alpha is the angle between these vectors.
  *
  * @param first first vector
  * @param second second vector
  * @return dot product of first and second
  */
double MBVec3::Dot( const MBVec3 &first, const MBVec3 &second )
{
	return first.Dot( second );
}

/**
  * Calculates the cross product first x second of the given vectors and returns
  * the result
  *
  * @param first first vector
  * @param second second vector
  * @return cross product: first x second
  */
MBVec3 MBVec3::Cross( const MBVec3 &first, const MBVec3 &second )
{
	return first.Cross( second );
}

/**
  * Normalizes the given vector, which means that it is scaled to length 1,
  * and returns the result.
  *
  * @param vec vector to be normalized
  * @return normalized vector
  */
MBVec3 MBVec3::Normalize( const MBVec3 &vec )
{
	MBVec3 result = vec;
	result.Normalize();

	return result;
}